package fr.uparis10.miage.m1p1.employes;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

import fr.uparis10.miage.m1p1.core.Projet;
import fr.uparis10.miage.m1p1.exceptions.ProjetException;
import fr.uparis10.miage.m1p1.global.BudgetReasonChefProjEnum;
import fr.uparis10.miage.m1p1.global.ProjetBudgetStruct;

public class ChefProjet extends Manager {
	private static HashMap<BudgetReasonChefProjEnum,Double> MAX_BUDGET_QUOTA;
	static {
		MAX_BUDGET_QUOTA = new HashMap<BudgetReasonChefProjEnum, Double>();
		/* defines how much of the project budget can be used for certain activity;
		 * the sum of the quotas must be 1 */
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.DEVELOP, 0.2);
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.MANAGEMENT, 0.1);
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.OTHER, 0.1);
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.SCOPE, 0.2);
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.SUPPORT, 0.1);
		MAX_BUDGET_QUOTA.put(BudgetReasonChefProjEnum.TEST, 0.3);
	}
	
	private ArrayList<Projet> listeProjets = new ArrayList<Projet>();
	private HashMap<Projet, ProjetBudgetStruct> mBudgetUsage = new HashMap<Projet, ProjetBudgetStruct>();

	/* Constructors - START */
	public ChefProjet() {
		super();
	}

	public ChefProjet(int preferedEmplId, long preferedNumSS) {
		super(preferedEmplId, preferedNumSS);
	}

	public ChefProjet(int preferedEmplId, long preferedNumSS, Date joinDate) {
		super(preferedEmplId, preferedNumSS, joinDate);
	}

	public ChefProjet(int preferedEmplId, long preferedNumSS, Date joinDate,
			double budget, Date dateNomination) {
		super(preferedEmplId, preferedNumSS, joinDate, budget, dateNomination);
	}

	public ChefProjet(Projet p) {
		super();
		listeProjets.add(p);
	}

	public ChefProjet(ArrayList<Projet> pListe) {
		super();
		listeProjets.addAll(pListe);
	}

	/* Constructors - END */

	public void ajouterProjet(Projet p) {
		if (listeProjets.contains(p)) {
			/* the project is already managed */
			return;
		}
		// V�rifier qu'aucun autre chef est responsable sur le projet p
		ChefProjet currChef = p.getChefProjet();
		if (currChef == null) {
			listeProjets.add(p);
			p.setChefProjet(this);
		}
		else {
			/* (try to) remove the Projet from the list of the current Chef */
			currChef.listeProjets.remove(p);
			listeProjets.add(p);
			p.setChefProjet(this);
		}
		
		mBudgetUsage.put(p, new ProjetBudgetStruct());
		// well, the Project "wants" to know the list of his employees
		p.addEmploye(this);
	}

	public void supprimerProjet(Projet p) {
		listeProjets.remove(p);
		mBudgetUsage.remove(p);
		// end of work for this project
		p.removeEmploye(this);
	}

	/**
	 * Used to request some budget.
	 * 
	 * @param requestedBudget
	 * @param reason - format "ACTIVITY:PROJECT_NAME"
	 * @return the requested budget, or less
	 * @throws ProjetException, IllegalArgumentException, NullPointerException
	 */
	@Override
	public double requestBudget(double requestedBudget, String reason) {
		int sepIndex = reason.indexOf(':');
		if (sepIndex == -1) {
			throw new ProjetException("Le format de 'reason' est invalide; format correcte - 'ACTIVITY:PROJECT'");
		}
		
		String	activity = reason.substring(0, sepIndex),
				projName = reason.substring(sepIndex + 1);
		BudgetReasonChefProjEnum budgetReason;
		try {
			budgetReason = BudgetReasonChefProjEnum.valueOf(activity);
		} catch (IllegalArgumentException exc) {
			// the reason value is invalid; throw the exception
			throw exc;
		} catch (NullPointerException exc) {
			exc.printStackTrace();
			// something really went wrong; don't give him any budget anyway
			return 0;
		}
		
		// looping on the whole list of projects to see if we have this one
		Projet theProj = null;
		for (Projet aProj: listeProjets) {
			if (aProj != null && projName.equals(aProj.getThemeProjet())) {
				theProj = aProj;
				break;
			}
		}
		if (theProj == null) {
			// no such project found
			throw new ProjetException("Le Chef " + "[(" + getCodeEmploye() + ") " + getNom() + "] ne g\u00e9re pas le projet " + projName);			
		}

		return requestBudget(requestedBudget, theProj, budgetReason);
	}

	/**
	 * Used to request some budget.
	 * 
	 * @param requestedBudget
	 * @param reason
	 * @return the requested budget, or less
	 */
	public double requestBudget(double requestedBudget, Projet proj,
			BudgetReasonChefProjEnum reason) {
		ProjetBudgetStruct pBudget = mBudgetUsage.get(proj);
		Double usedBudget = pBudget.getUsage(reason);
		if (usedBudget == null) {
			usedBudget = (double) 0;
		}
		Double maxBudget;
		try { 
			maxBudget = MAX_BUDGET_QUOTA.get(reason) * proj.getBudjetProjet();
		} catch (NullPointerException exc) {
			maxBudget = (double) 0;
		}
		double availableBudget = maxBudget - usedBudget;

		double allowedBudget = availableBudget < requestedBudget ? availableBudget
				: requestedBudget;

		pBudget.addUsage(reason, allowedBudget);
		return allowedBudget;
	}

	@Override
	public int calcBonus() {
		double bonusRate;
		switch (indice) {
		case A:
			bonusRate = 0.1;
			break;
		case B:
			bonusRate = 0.05;
			break;
		default:
			bonusRate = 0;
		}
		double bonus = salaire * bonusRate;
		return (int) bonus;
	}
}